package com.umeox.watch.moto.chat.adapter

import android.content.Context
import android.graphics.drawable.AnimationDrawable
import android.text.SpannableString
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.LinearInterpolator
import android.view.animation.RotateAnimation
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.RoundedCornersTransformation
import com.bumptech.glide.load.resource.bitmap.CircleCrop
import com.bumptech.glide.request.RequestOptions
import com.github.chrisbanes.photoview.PhotoView
import com.umeox.moto.common.log.Logger
import com.umeox.moto.common.recorder.PlayAudioTask
import com.umeox.moto.common.rvadapter.MultiItemTypeAdapter
import com.umeox.moto.common.rvadapter.ViewHolder
import com.umeox.moto.common.rvadapter.wrapper.ItemViewDelegate
import com.umeox.moto.common.utils.FileUtils
import com.umeox.moto.watch.themes.dialog.AlertDialog
import com.umeox.moto.watch.themes.skin.loader.ResourceManager
import com.umeox.watch.moto.chat.R
import com.umeox.watch.moto.chat.base.GlideApp
import com.umeox.watch.moto.chat.bean.GroupMemberDetail
import com.umeox.watch.moto.chat.db.ChatMessage
import com.umeox.watch.moto.chat.db.ContactInfo
import com.umeox.watch.moto.chat.db.MessageDelegate
import com.umeox.watch.moto.chat.proto.ChatMsgProtos
import com.umeox.watch.moto.chat.utils.EmoticonConstants
import com.umeox.watch.moto.chat.utils.Utility
import com.umeox.watch.moto.dataservice.DataProvider
import com.umeox.watch.moto.dataservice.proxy.ChatProxy
import java.io.File
import java.lang.reflect.Array.getLength
import java.util.Locale

/**
 * Created by Rambo 2021/8/23
 * Describe:
 */
class WatchMessageMultiItemAdapter(
    private val context: Context,
    private val mContact: ContactInfo
) : MultiItemTypeAdapter<ChatMessage>(context) {

    private var chatMessages: MutableList<ChatMessage?>? = null
    private val mChatMsgSelectedList: MutableList<ChatMessage> = ArrayList()
    private var playAudioTask: PlayAudioTask? = null
    private var playingViewPosition = -1
    private var viewHeader = false
    private var viewFooter = false
    private lateinit var bigPictureViewer: BigPictureViewer
    private var mAnimationDrawable: AnimationDrawable? = null

    private var groupMemberList: List<GroupMemberDetail>? = null

    init {
        MessageDelegate.getManager().updateReadStateWithoutVoiceChat(mContact)
//        MessageDelegate.getManager().refreshMessage(mContact)
        for (viewType in ViewType.values()) {
            when (viewType) {
                ViewType.INCOMING_VOICE -> addItemViewDelegate(
                    viewType.type,
                    IncomingVoiceItemDelegate()
                )

                ViewType.INCOMING_PHOTO -> addItemViewDelegate(
                    viewType.type,
                    IncomingImgItemDelegate()
                )

                ViewType.INCOMING_EMOJI -> addItemViewDelegate(
                    viewType.type,
                    IncomingEmojiItemDelegate()
                )

                ViewType.INCOMING_TEXT -> addItemViewDelegate(
                    viewType.type,
                    IncomingSmsItemDelegate()
                )

                ViewType.OUTGOING_TEXT -> addItemViewDelegate(
                    viewType.type,
                    OutgoingSmsItemDelegate()
                )

                ViewType.OUTGOING_VOICE -> addItemViewDelegate(
                    viewType.type,
                    OutgoingVoiceItemDelegate()
                )

                ViewType.OUTGOING_PHOTO -> addItemViewDelegate(
                    viewType.type,
                    OutgoingImgItemDelegate()
                )

                ViewType.OUTGOING_EMOJI -> addItemViewDelegate(
                    viewType.type,
                    OutgoingEmojiItemDelegate()
                )

                else -> addItemViewDelegate(viewType.type, EmptyItemDelegate())
            }
        }
        if (mContact.isGroup) {
            groupMemberList = getGroupMemberList(mContact.friendId)
        }
    }

    private fun getGroupMemberList(groupId: String): List<GroupMemberDetail> {
        val list = mutableListOf<GroupMemberDetail>()
        val memberList = DataProvider.getIMGroupMembersByGroupId(groupId)
        if (!memberList.isNullOrEmpty()) {
            for (temp in memberList) {
                val task: GroupMemberDetail? = GroupMemberDetail.convertFromValues(temp)
                if (task != null) {
                    list.add(task)
                }
            }
        }
        return list
    }


    fun getChatMsgSelectedList(): List<ChatMessage> {
        mChatMsgSelectedList.clear()
        for (data in mDatas) {
            if (data.selected) {
                mChatMsgSelectedList.add(data)
            }
        }
        return mChatMsgSelectedList
    }


    fun addOrRemoveSelected(position: Int) {
        val photo = mDatas[position]
        photo.selected = !photo.selected
        notifyItemChanged(position)
    }


    fun resetSelectedChatMsgs() {
        if (mDatas == null) {
            return
        }
        for (i in 0 until mDatas.size) {
            val message = mDatas[i]
            if (message.selected) {
                message.selected = false
                notifyItemChanged(i)
            }
        }
        mChatMsgSelectedList.clear()
    }

    fun setData(messages: MutableList<ChatMessage?>?) {
        val positionStart = if (chatMessages == null) 0 else chatMessages!!.size - 1
        chatMessages = messages
        val itemCount = if (chatMessages == null) 0 else chatMessages!!.size - positionStart
        if (viewHeader) {
            addHeaderView()
        }
        if (viewFooter) {
            addFooterView()
        }
        datas = chatMessages
        Logger.i("positionStart=$positionStart,itemCount = $itemCount")
//        if (positionStart > 0 || itemCount > 0) {
//            notifyItemRangeChanged(positionStart, itemCount)
//        }
    }

    private fun getItem(position: Int): ChatMessage? {
        return if (datas != null && position < datas.size) {
            datas[position]
        } else null
    }


    fun getPositionByItem(chatMessage: ChatMessage): Int {
        if (datas != null && datas.isNotEmpty()) {
            for ((position, chat) in datas.withIndex()) {
                if (chat != null && chat.id == chatMessage.id) {
                    return position
                }
            }
        }
        return -1
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getItemViewType(position: Int): Int {
        val chatMessage = getItem(position)
        var viewType = ViewType.EMPTY_VIEW
        if (chatMessage != null) {
            val msgType: Int = chatMessage.msgType
            val from: String = chatMessage.fuid
            if (msgType == ChatMsgProtos.ChatMsgType.VOICE_VALUE
            ) {
                viewType = if (isIncoming(from)) {
                    ViewType.INCOMING_VOICE //接收手机APP发送的语音消息
                } else {
                    ViewType.OUTGOING_VOICE //手表发送的语音消息
                }
            } else if (msgType == ChatMsgProtos.ChatMsgType.PHOTO_VALUE) {
                viewType = if (isIncoming(from)) {
                    ViewType.INCOMING_PHOTO //接收手表发送的照片
                } else {
                    ViewType.OUTGOING_PHOTO //手表发送的照片
                }
            } else if (msgType == ChatMsgProtos.ChatMsgType.STICKER_VALUE || msgType == ChatMsgProtos.ChatMsgType.SMALL_EXPRESSION_VALUE || msgType == ChatMsgProtos.ChatMsgType.TEXT_STICKER_VALUE) {
                viewType = if (isIncoming(from)) {
                    ViewType.INCOMING_EMOJI //手表收到的表情
                } else {
                    ViewType.OUTGOING_EMOJI //手表发送的表情
                }
            } else {
                viewType = if (isIncoming(from)) {
                    ViewType.INCOMING_TEXT //手表收到的文本
                } else {
                    ViewType.OUTGOING_TEXT //手表发送的文本
                }
            }
        }
        return viewType.type
    }

    fun stopPlay() {
        if (playAudioTask != null && playAudioTask!!.isPlaying) {
            playAudioTask?.stop()
        }
    }

    fun release() {
        if (playAudioTask != null) {
            playAudioTask?.release()
        }
    }

    private fun isIncoming(from: String?): Boolean {
        if (mContact.isGroup) { //群聊
            return from != null && from != DataProvider.getHolderId()
        }
        return from != null && from == mContact.friendId
    }

    fun viewEmptyHeaderView() {
        if (!viewHeader) {
            viewHeader = true
            addHeaderView()
        }
    }

    private fun addHeaderView() {
        chatMessages?.add(0, null)
    }

    fun viewEmptyFooterView() {
        if (!viewFooter) {
            viewFooter = true
            addFooterView()
        }
    }

    private fun addFooterView() {
        chatMessages?.add(null)
    }

    private fun isHeaderViewPos(position: Int): Boolean {
        return if (viewHeader) {
            position == 0
        } else false
    }

    private fun isFooterViewPos(position: Int): Boolean {
        return if (viewFooter) {
            position == datas.size - 1
        } else false
    }

    private fun isFirstViewPosition(position: Int): Boolean {
        return (viewHeader && position == 1
                || !viewHeader && position == 0)
    }

    private fun inVisible(recyclerView: RecyclerView?, position: Int): Boolean {
        if (recyclerView != null && position > -1 && position < itemCount) {
            val layoutManager = recyclerView.layoutManager
            var firstPosition = -1
            var lastPosition = -1
            if (layoutManager is LinearLayoutManager) {
                firstPosition = layoutManager.findFirstVisibleItemPosition()
                lastPosition = layoutManager.findLastVisibleItemPosition()
            }
            Logger.d("inVisible->position:$position, count:$itemCount, start:$firstPosition, end:$lastPosition")
            var i = firstPosition
            val j = lastPosition
            while (i <= j) {
                if (position == i) {
                    return true
                }
                i++
            }
        }
        return false
    }

    private fun onHolderClick(holder: ViewHolder, view: View, message: ChatMessage, position: Int) {
        when (view.id) {
            R.id.ivState -> {
                //取消正在发送或者下载消息，可以让用户重新操作
                if (message.state == ChatMsgProtos.ChatMsgState.STATE_DOWNLOADING_VALUE) {
                    MessageDelegate.getManager()
                        .cancelProcessing(message, ChatMsgProtos.ChatMsgState.STATE_DOWNLOAD_FAILED)
                    return
                } else if (message.state == ChatMsgProtos.ChatMsgState.STATE_SENDING_VALUE) {
                    MessageDelegate.getManager()
                        .cancelProcessing(message, ChatMsgProtos.ChatMsgState.STATE_SEND_FAILED)
                    return
                }
                //重新下载或者发送
                if (isIncoming(message.fuid)) {
                    //重新下载
                    MessageDelegate.getManager()
                        .reloadMessage(ChatProxy.fetchBinder(), mContact, message)
                } else {
                    //重新发送
                    MessageDelegate.getManager()
                        .handleOutgoingMessage(ChatProxy.fetchBinder(), mContact, message, true)
                }
//                notifyDataSetChanged()
                notifyItemChanged(position)
            }

            R.id.ivPlay -> {
                //语音聊天的点击播放
                //下载失败不让点击
                Log.d("zhanlv", "onHolderClick: ")
                val voiceIv = view as ImageView

                if (message.state == ChatMsgProtos.ChatMsgState.STATE_DOWNLOAD_FAILED_VALUE) {
                    return
                }

                if (playAudioTask == null) {
                    playAudioTask = PlayAudioTask(mContext)
                }
                //停止当前正在播放的音频
                if (playAudioTask!!.isPlaying) {
                    stopPlay()
                    if (message.filePath.equals(playAudioTask?.dataSource)) {
                        return
                    }
                }
                playAudioTask?.start(message.filePath, object : PlayAudioTask.AudioPlayCallback {
                    override fun onStart(duration: Int) {
                        voiceIv.setImageDrawable(
                            if (holder.itemViewType == ViewType.INCOMING_VOICE.type)
                                ResourceManager.getInstance()
                                    .getDrawable(R.drawable.incoming_voice_anim)
                            else ResourceManager.getInstance()
                                .getDrawable(R.drawable.outgoing_voice_anim)
                        )
                        mAnimationDrawable = voiceIv.drawable as AnimationDrawable
                        mAnimationDrawable?.start()
                        Logger.i(
                            "开始播放语音文件>>>" + holder.adapterPosition
                                .toString() + "," + message.filePath
                        )
                        playingViewPosition = holder.adapterPosition
                        //处理未读标记
                        if (message.unRead == ChatMsgProtos.ChatMsgState.STATE_UNREAD_VALUE) {
                            Logger.i("标记未读消息为已读")
                            MessageDelegate.getManager().setReadState(mContact.id, message.id)
                            message.unRead = (ChatMsgProtos.ChatMsgState.STATE_READ_VALUE)
                        }
                    }

                    override fun onPlaying(progress: Int) {

                    }

                    override fun onCompletion() {
                        Logger.i("播放完成>>>" + message.filePath)
                        finish()
                    }

                    override fun onStop() {
                        Logger.i("停止播放>>>" + message.filePath)
                        finish()
                    }

                    override fun onError(error: String) {
                        Logger.i("播放语音失败>>>$error")
                        finish()
                    }

                    private fun finish() {
                        Log.d("zhanlv", "finish: ")


                        mAnimationDrawable?.stop()
                        mAnimationDrawable = null
                        voiceIv.setImageDrawable(
                            if (holder.itemViewType == ViewType.INCOMING_VOICE.type)
                                ResourceManager.getInstance()
                                    .getDrawable(R.drawable.ic_left_voice_playing_level_1)
                            else ResourceManager.getInstance()
                                .getDrawable(R.drawable.ic_right_voice_playing_level_1)
                        )
                        playingViewPosition = -1
                    }
                })
            }

            else -> {
            }
        }
    }

    private fun viewBigPicture(url: String) {
        bigPictureViewer = BigPictureViewer(context)
        bigPictureViewer.show(url)
    }


    private enum class ViewType(val type: Int) {
        /**
         * 语聊消息类型
         */
        EMPTY_VIEW(0),
        INCOMING_VOICE(1),
        OUTGOING_VOICE(2),
        INCOMING_PHOTO(3),
        OUTGOING_PHOTO(4),
        INCOMING_EMOJI(5),
        OUTGOING_EMOJI(6),
        INCOMING_TEXT(7),
        OUTGOING_TEXT(8),
        OUTGOING_VIDEO(9),
        INCOMING_VIDEO(10);

        companion object {
            fun forNumber(value: Int): ViewType {
                return when (value) {
                    1 -> INCOMING_VOICE
                    2 -> OUTGOING_VOICE
                    3 -> INCOMING_PHOTO
                    4 -> OUTGOING_PHOTO
                    5 -> INCOMING_EMOJI
                    6 -> OUTGOING_EMOJI
                    7 -> INCOMING_TEXT
                    8 -> OUTGOING_TEXT
                    9 -> OUTGOING_VIDEO
                    10 -> INCOMING_VIDEO
                    else -> EMPTY_VIEW
                }
            }
        }
    }

    private abstract inner class BaseChatMessageItem : ItemViewDelegate<ChatMessage> {
        val STATE_LOADING = 1
        val STATE_FAILED = -1
        val STATE_NONE = 0
        fun showMessageTimeView(position: Int): Boolean {
            if (isHeaderViewPos(position)
                || isFooterViewPos(position)
            ) {
                return false
            }
            return when {
                isFirstViewPosition(position) -> {
                    true
                }

                position < itemCount -> {
                    val preItemTime: Long = datas[position - 1].msgTime
                    val currentItemTime: Long = datas[position].msgTime
                    currentItemTime - preItemTime >= 5 * 60 * 1000
                }

                else -> {
                    false
                }
            }
        }

        /**
         * 下载、上传、失败状态下， View呈现不同状态
         */
        fun changeState(ivState: ImageView, state: Int) {
            when (state) {
                STATE_LOADING -> {
                    ivState.visibility = View.VISIBLE
                    val rotate = RotateAnimation(
                        0f,
                        360f,
                        Animation.RELATIVE_TO_SELF,
                        0.5f,
                        Animation.RELATIVE_TO_SELF,
                        0.5f
                    )
                    val lin = LinearInterpolator()
                    rotate.interpolator = lin
                    rotate.duration = 800 //设置动画持续时间
                    rotate.repeatCount = -1 //设置重复次数
                    rotate.fillAfter = false //动画执行完后是否停留在执行完的状态
                    ivState.animation = rotate
                    rotate.start()
                }

                STATE_FAILED -> {
                    if (ivState.animation is RotateAnimation) {
                        ivState.animation.cancel()
                    }
                    ivState.visibility = View.VISIBLE
                }

                else -> {
                    ivState.visibility = View.GONE
                }
            }
        }
    }

    private inner class EmptyItemDelegate : BaseChatMessageItem() {

        override fun getItemViewLayoutId(): Int = R.layout.recycle_item_empty

        override fun isForViewType(message: ChatMessage, position: Int): Boolean {
            return getItemViewType(position) == ViewType.EMPTY_VIEW.type
        }

        override fun convert(holder: ViewHolder, message: ChatMessage, position: Int) {
            Logger.d("EmptyItemDelegate->convert->position:$position")
            val params: ViewGroup.LayoutParams = holder.convertView.layoutParams
            if (isHeaderViewPos(position)) {
                params.height = Utility.dpToPx(context, 50F).toInt()
            } else {
                params.height = Utility.dpToPx(context, 80F).toInt()
            }
            holder.convertView.layoutParams = params
        }
    }

    private inner class IncomingVoiceItemDelegate : BaseChatMessageItem() {

        override fun getItemViewLayoutId(): Int = R.layout.recycle_item_voice_incoming

        override fun isForViewType(message: ChatMessage?, position: Int): Boolean {
            return getItemViewType(position) == ViewType.INCOMING_VOICE.type
        }

        override fun convert(holder: ViewHolder, message: ChatMessage, position: Int) {
            Logger.d("IncomingVoiceItemDelegate->convert->position:$position")
            val memberDetail = groupMemberList?.find {
                it.memberId == message.fuid
            }
            showAvatar(
                holder.getView(R.id.ivAvatar),
                memberDetail?.avatar ?: DataProvider.getAvatarByFriendId(message.fuid)

            )
            holder.setText(
                R.id.tv_name,
                memberDetail?.name ?: DataProvider.getNickNameByFriendId(message.fuid)
            )
            holder.setText(
                R.id.tvLength,
                "${
                    String.format(
                        Locale.getDefault(),
                        "%d",
                        Math.round(message.length.toFloat() / 1000)
                    )
                }\""
            )
            val ivState: ImageView = holder.getView(R.id.ivState)
            val ivUnRead: ImageView = holder.getView(R.id.ivUnread)
            when (message.state) {
                ChatMsgProtos.ChatMsgState.STATE_DOWNLOADING_VALUE -> {
                    changeState(ivState, STATE_LOADING)
                }

                ChatMsgProtos.ChatMsgState.STATE_DOWNLOAD_FAILED_VALUE -> {
                    changeState(ivState, STATE_FAILED)
                }

                else -> {
                    changeState(ivState, STATE_NONE)
                    if (message.unRead == ChatMsgProtos.ChatMsgState.STATE_UNREAD_VALUE) {
                        ivUnRead.visibility = View.VISIBLE
                    } else {
                        ivUnRead.visibility = View.GONE
                    }
                }
            }
            if (showMessageTimeView(position)) {
                holder.setVisible(R.id.tvWhen, true)
                holder.setText(
                    R.id.tvWhen,
                    Utility.intervalDate(context, message.msgTime)
                )
            } else {
                holder.setVisible(R.id.tvWhen, false)
            }
            val onClickListener =
                View.OnClickListener { view: View ->
                    if (message.unRead == ChatMsgProtos.ChatMsgState.STATE_UNREAD_VALUE) {
                        ivUnRead.visibility = View.GONE
                    }

                    onHolderClick(
                        holder,
                        view,
                        message,
                        position
                    )
                }
            holder.setOnClickListener(R.id.ivPlay, onClickListener)
            ivState.setOnClickListener(onClickListener)
        }
    }

    private inner class IncomingImgItemDelegate : BaseChatMessageItem() {

        override fun getItemViewLayoutId(): Int = R.layout.recycle_item_img_incoming

        override fun isForViewType(message: ChatMessage, position: Int): Boolean {
            return getItemViewType(position) == ViewType.INCOMING_PHOTO.type
        }

        override fun convert(holder: ViewHolder, message: ChatMessage, position: Int) {
            Logger.d("IncomingImgItemDelegate->convert->position:$position")
            val memberDetail = groupMemberList?.find {
                it.memberId == message.fuid
            }
            showAvatar(
                holder.getView(R.id.ivAvatar),
                memberDetail?.avatar ?: DataProvider.getAvatarByFriendId(message.fuid)
            )
            holder.setText(
                R.id.tv_name,
                memberDetail?.name ?: DataProvider.getNickNameByFriendId(message.fuid)
            )
            val content: ImageView = holder.getView(R.id.content)
            val url: String? = message.filePath
            if (FileUtils.isFileExists(url)) {
                content.load(File(url!!)) {
                    error(R.drawable.bg_msg_photo)
                    transformations(
                        RoundedCornersTransformation(
                            topLeft = 4f,
                            topRight = 4f,
                            bottomLeft = 4f,
                            bottomRight = 4f
                        )
                    )
                }
                content.setOnClickListener {
                    viewBigPicture(url)
                }
            }
            val ivState: ImageView = holder.getView(R.id.ivState)
            when (message.state) {
                ChatMsgProtos.ChatMsgState.STATE_SENDING_VALUE -> {
                    changeState(ivState, STATE_LOADING)
                }

                ChatMsgProtos.ChatMsgState.STATE_SEND_FAILED_VALUE -> {
                    changeState(ivState, STATE_FAILED)
                }

                else -> {
                    changeState(ivState, STATE_NONE)
                }
            }
            if (showMessageTimeView(position)) {
                holder.setVisible(R.id.tvWhen, true)
                holder.setText(
                    R.id.tvWhen,
                    Utility.intervalDate(context, message.msgTime)
                )
            } else {
                holder.setVisible(R.id.tvWhen, false)
            }
            ivState.setOnClickListener { view: View ->
                onHolderClick(
                    holder,
                    view,
                    message,
                    position
                )
            }
        }
    }

    private inner class IncomingSmsItemDelegate : BaseChatMessageItem() {

        override fun getItemViewLayoutId(): Int = R.layout.recycle_item_sms_incoming

        override fun isForViewType(message: ChatMessage, position: Int): Boolean {
            return getItemViewType(position) == ViewType.INCOMING_TEXT.type
        }

        override fun convert(holder: ViewHolder, message: ChatMessage, position: Int) {
            Logger.d("IncomingSmsItemDelegate->convert->position:$position")
            val memberDetail = groupMemberList?.find {
                it.memberId == message.fuid
            }
            showAvatar(
                holder.getView(R.id.ivAvatar),
                memberDetail?.avatar ?: DataProvider.getAvatarByFriendId(message.fuid)
            )
            holder.setText(
                R.id.tv_name,
                memberDetail?.name ?: DataProvider.getNickNameByFriendId(message.fuid)
            )
            holder.setText(R.id.content, message.msgBody)
            if (showMessageTimeView(position)) {
                holder.setVisible(R.id.tvWhen, true)
                holder.setText(
                    R.id.tvWhen,
                    Utility.intervalDate(context, message.msgTime)
                )
            } else {
                holder.setVisible(R.id.tvWhen, false)
            }
        }
    }

    private fun showAvatar(ivAvatar: ImageView, photoUrl: String?) {
//        ivAvatar.load(photoUrl) {
//            placeholder(R.drawable.default_avatar)
//            error(R.drawable.default_avatar)
//            size(36,36)
//            transformations(CircleCropTransformation())
//        }

        GlideApp.with(mContext)
            .load(photoUrl)
            .placeholder(R.drawable.default_avatar)
            .error(R.drawable.default_avatar)
            .apply(RequestOptions.bitmapTransform(CircleCrop()))
            .into(ivAvatar)
    }

    private inner class OutgoingSmsItemDelegate : BaseChatMessageItem() {

        override fun getItemViewLayoutId(): Int = R.layout.recycle_item_sms_outgoing

        override fun isForViewType(message: ChatMessage, position: Int): Boolean {
            return getItemViewType(position) == ViewType.OUTGOING_TEXT.type
        }

        override fun convert(holder: ViewHolder, message: ChatMessage, position: Int) {
            Logger.d("OutgoingSmsItemDelegate->convert->position:$position")
            showAvatar(holder.getView(R.id.ivAvatar), DataProvider.getAvatar())
            holder.setText(R.id.tv_name, DataProvider.getNickname())
            holder.setText(R.id.content, message.msgBody)
            val ivState: ImageView = holder.getView(R.id.ivState)
            when (message.state) {
                ChatMsgProtos.ChatMsgState.STATE_SENDING_VALUE -> {
                    changeState(ivState, STATE_LOADING)
                }

                ChatMsgProtos.ChatMsgState.STATE_SEND_FAILED_VALUE -> {
                    changeState(ivState, STATE_FAILED)
                }

                else -> {
                    changeState(ivState, STATE_NONE)
                }
            }
            if (showMessageTimeView(position)) {
                holder.setVisible(R.id.tvWhen, true)
                holder.setText(
                    R.id.tvWhen,
                    Utility.intervalDate(context, message.msgTime)
                )
            } else {
                holder.setVisible(R.id.tvWhen, false)
            }

            val onClickListener =
                View.OnClickListener { view: View ->
                    onHolderClick(
                        holder,
                        view,
                        message,
                        position
                    )
                }
            ivState.setOnClickListener(onClickListener)
        }
    }

    private inner class IncomingEmojiItemDelegate : BaseChatMessageItem() {

        override fun getItemViewLayoutId(): Int = R.layout.recycle_item_emoji_incoming

        override fun isForViewType(message: ChatMessage, position: Int): Boolean {
            return getItemViewType(position) == ViewType.INCOMING_EMOJI.type
        }

        override fun convert(holder: ViewHolder, message: ChatMessage, position: Int) {
            Logger.d("IncomingEmojiItemDelegate->convert->position:$position")
            val memberDetail = groupMemberList?.find {
                it.memberId == message.fuid
            }
            showAvatar(
                holder.getView(R.id.ivAvatar),
                memberDetail?.avatar ?: DataProvider.getAvatarByFriendId(message.fuid)
            )
            holder.setText(
                R.id.tv_name,
                memberDetail?.name ?: DataProvider.getNickNameByFriendId(message.fuid)
            )
            //解析Emoji
            val sp: SpannableString =
                EmoticonConstants.spannableString(context, message.msgBody)
            (holder.getView(R.id.content) as TextView).text = sp
            if (showMessageTimeView(position)) {
                holder.setVisible(R.id.tvWhen, true)
                holder.setText(
                    R.id.tvWhen,
                    Utility.intervalDate(context, message.msgTime)
                )
            } else {
                holder.setVisible(R.id.tvWhen, false)
            }
        }
    }

    private inner class OutgoingVoiceItemDelegate : BaseChatMessageItem() {

        override fun getItemViewLayoutId(): Int = R.layout.recycle_item_voice_outgoing

        override fun isForViewType(message: ChatMessage, position: Int): Boolean {
            return getItemViewType(position) == ViewType.OUTGOING_VOICE.type
        }

        override fun convert(holder: ViewHolder, message: ChatMessage, position: Int) {
            Logger.d("OutgoingVoiceItemDelegate->convert->position:$position")
            showAvatar(holder.getView(R.id.ivAvatar), DataProvider.getAvatar())
            holder.setText(R.id.tv_name, DataProvider.getNickname())
            holder.setText(
                R.id.tvLength,
                "${
                    String.format(
                        Locale.getDefault(),
                        "%d",
                        Math.round(message.length.toFloat() / 1000)
                    )
                }\""
            )
            val ivState: ImageView = holder.getView(R.id.ivState)
            when (message.state) {
                ChatMsgProtos.ChatMsgState.STATE_SENDING_VALUE -> {
                    changeState(ivState, STATE_LOADING)
                }

                ChatMsgProtos.ChatMsgState.STATE_SEND_FAILED_VALUE -> {
                    changeState(ivState, STATE_FAILED)
                }

                else -> {
                    changeState(ivState, STATE_NONE)
                }
            }
            if (showMessageTimeView(position)) {
                holder.setVisible(R.id.tvWhen, true)
                holder.setText(
                    R.id.tvWhen,
                    Utility.intervalDate(context, message.msgTime)
                )
            } else {
                holder.setVisible(R.id.tvWhen, false)
            }
            val onClickListener =
                View.OnClickListener { view: View ->
                    onHolderClick(
                        holder,
                        view,
                        message,
                        position
                    )
                }
            holder.setOnClickListener(R.id.ivPlay, onClickListener)
            ivState.setOnClickListener(onClickListener)
        }
    }

    private inner class OutgoingImgItemDelegate : BaseChatMessageItem() {

        override fun getItemViewLayoutId(): Int = R.layout.recycle_item_img_outgoing

        override fun isForViewType(message: ChatMessage, position: Int): Boolean {
            return getItemViewType(position) == ViewType.OUTGOING_PHOTO.type
        }

        override fun convert(holder: ViewHolder, message: ChatMessage, position: Int) {
            Logger.d("OutgoingImgItemDelegate->convert->position:$position")
            showAvatar(holder.getView(R.id.ivAvatar), DataProvider.getAvatar())
            holder.setText(R.id.tv_name, DataProvider.getNickname())
            val content: ImageView = holder.getView(R.id.content)
            var url: String? = message.filePath
            if (!FileUtils.isFileExists(url)) {
                url = message.msgBody;
            }
            content.load(File(url!!)) {
                error(R.drawable.bg_msg_photo)
                transformations(
                    RoundedCornersTransformation(
                        topLeft = 4f,
                        topRight = 4f,
                        bottomLeft = 4f,
                        bottomRight = 4f
                    )
                )
            }
            content.setOnClickListener {
                viewBigPicture(url)
            }
            val ivState: ImageView = holder.getView(R.id.ivState)
            when (message.state) {
                ChatMsgProtos.ChatMsgState.STATE_SENDING_VALUE -> {
                    changeState(ivState, STATE_LOADING)
                }

                ChatMsgProtos.ChatMsgState.STATE_SEND_FAILED_VALUE -> {
                    changeState(ivState, STATE_FAILED)
                }

                else -> {
                    changeState(ivState, STATE_NONE)
                }
            }
            if (showMessageTimeView(position)) {
                holder.setVisible(R.id.tvWhen, true)
                holder.setText(
                    R.id.tvWhen,
                    Utility.intervalDate(context, message.msgTime)
                )
            } else {
                holder.setVisible(R.id.tvWhen, false)
            }
            val onClickListener =
                View.OnClickListener { view: View ->
                    onHolderClick(
                        holder,
                        view,
                        message,
                        position
                    )
                }
            ivState.setOnClickListener(onClickListener)
        }
    }

    private inner class OutgoingEmojiItemDelegate : BaseChatMessageItem() {

        override fun getItemViewLayoutId(): Int = R.layout.recycle_item_emoji_outgoing

        override fun isForViewType(message: ChatMessage, position: Int): Boolean {
            return getItemViewType(position) == ViewType.OUTGOING_EMOJI.type
        }

        override fun convert(holder: ViewHolder, message: ChatMessage, position: Int) {
            Logger.d("OutgoingEmojiItemDelegate->convert->position:$position")
            showAvatar(holder.getView(R.id.ivAvatar), DataProvider.getAvatar())
            holder.setText(R.id.tv_name, DataProvider.getNickname())
            //解析Emoji
            val sp: SpannableString =
                EmoticonConstants.spannableString(context, message.msgBody)
            (holder.getView(R.id.content) as TextView).text = sp
            val ivState: ImageView = holder.getView(R.id.ivState)
            when (message.state) {
                ChatMsgProtos.ChatMsgState.STATE_SENDING_VALUE -> {
                    changeState(ivState, STATE_LOADING)
                }

                ChatMsgProtos.ChatMsgState.STATE_SEND_FAILED_VALUE -> {
                    changeState(ivState, STATE_FAILED)
                }

                else -> {
                    changeState(ivState, STATE_NONE)
                }
            }
            if (showMessageTimeView(position)) {
                holder.setVisible(R.id.tvWhen, true)
                holder.setText(
                    R.id.tvWhen,
                    Utility.intervalDate(context, message.msgTime)
                )
            } else {
                holder.setVisible(R.id.tvWhen, false)
            }
            val onClickListener =
                View.OnClickListener { view: View ->
                    onHolderClick(
                        holder,
                        view,
                        message,
                        position
                    )
                }
            ivState.setOnClickListener(onClickListener)
        }
    }

    private class BigPictureViewer(context: Context) {
        private val photoView: PhotoView
        private val bigPicDialog: AlertDialog

        fun show(url: String) {
            photoView.load(File(url))
            bigPicDialog.show()
        }

        init {
            val view: View = LayoutInflater.from(context).inflate(R.layout.dialog_photo_entry, null)
            photoView = view.findViewById(R.id.ivContent)
            bigPicDialog = AlertDialog.Builder(context).setView(view).setCancelable(true).create()
            photoView.setOnViewTapListener { _, _, _ -> bigPicDialog.cancel() }
        }
    }
}